<?php

/**
 * 代码复制
 * 模型方法继承
 * Trait extendMethod
 */
trait ModelTrait
{
    /**
     * 对保存到数据库的数据进行处理
     * @access protected
     * @param mixed $data 要操作的数据
     * @return boolean
     */
    protected function _facade($data)
    {
        // 检查序列化字段
        $data = $this->serializeField($data);
        return parent::_facade($data);
    }

    /**
     * 处理序列化字段
     * 基于官方高级模型的改进版
     * @param $data
     */
    protected function serializeField(&$data)
    {
        // 检查序列化字段
        if (!empty($this->serializeField)) {
            // 定义方式  $this->serializeField = array('ser'=>array('name','email'));
            foreach ($this->serializeField as $key => $val) {
                if (!$data[$key]) continue;// create方法会过滤掉不存在的字段 所以配置好的序列化字段在create方法下永远不能生效
                $serialize = array();
                foreach ($val as $name) {
                    if (isset($data[$key][$name])) {
                        $serialize[$name] = $data[$key][$name];
                        unset($data[$key][$name]);
                    }
                }
                if (!empty($serialize))
                    $data[$key] = serialize($serialize);
            }
        }
        return $data;
    }

    // 检查返回数据的序列化字段
    protected function checkSerializeField(&$result)
    {
        // 检查序列化字段
        if (!empty($this->serializeField)) {
            foreach ($this->serializeField as $key => $val) {
                if (isset($result[$key]))
                    $result[$key] = unserialize($result[$key]);
            }
        }
        return $result;
    }

    /**
     * 存在则更新否则新增
     * @param $data 插入数据
     * @param $map 条件
     * @return bool|mixed
     */
    public function in2replace($data, $map = array())
    {
        // 此处修复 为了保留原有的连贯操作 使用M方法处理 2019 01 14
        if (M($this->getModelName())->where($map)->count() > 0) {
            return $this->where($map)->save($data);
        }
        return $this->add($data);
    }

    /**
     * 分页查询数据
     * @access public
     * @param mixed $pageopt 分页参数
     * @param mixed $options 表达式参数
     * @return mixed
     */
    function findPage($pageopt = null, $count = false, $options = array())
    {
        // 分析表达式
        $options = $this->_parseOptions($options);
        $param   = array();
        // 如果没有传入总数，则自动根据条件进行统计
        if ($count === false) {
            // 查询总数
            $count_options          = $options;
            $count_options['limit'] = 1;
            $count_options['field'] = 'count(1) as count';
            // 去掉统计时的排序提高效率
            unset($count_options['order']);
            $result = $this->db->select($count_options);

            $count = $result[0]['count'];
            unset($result);
            unset($count_options);
        }
        // 如果查询总数大于0
        if ($count > 0) {
            // 解析分页参数
            $confSize = intval(C('LIST_NUMBERS'));
            $pagesize = $confSize ? $confSize : 20;
            if (is_numeric($pageopt)) {
                $pagesize = intval($pageopt);
            } elseif (is_array($pageopt)) {
                if (isset($pageopt['size'])) {
                    $pagesize = intval($pageopt['size']);
                }
                $param = $pageopt['param'];
                if (!$param)
                    $param = I('request');
            }

            $p       = new Think\Page($count, $pagesize, $param);
            $html    = $p->show();
            $nowPage = I('request.' . C('VAR_PAGE'), 1, 'intval');
            // 查询数据
            $options['limit'] = $p->firstRow . ',' . $p->listRows;
            $resultSet        = $this->select($options);

            if ($resultSet) {
                $this->dataList = $resultSet;
            } else {
                $resultSet = '';
            }

            // 输出控制
            $output['count']      = intval($count);
            $output['totalPages'] = intval($p->totalPages);
            $output['totalRows']  = intval($p->totalRows);
            $output['nowPage']    = intval($nowPage);
            $output['html']       = $html;
            $output['data']       = $resultSet;
            unset($resultSet, $p, $count);
        } else {
            $output['count']      = 0;
            $output['totalPages'] = 0;
            $output['totalRows']  = 0;
            $output['nowPage']    = 1;
            $output['html']       = '';
            $output['data']       = [];
        }
        $output['code'] = 0;
        // 输出数据
        return $output;
    }

    /**
     * 重新格式化映射关系
     * @param $excel_head_map
     * @return mixed
     */
    public function format_excel_head($excel_head_map)
    {
        if ($excel_head_map) {
            require_once APP_PATH . 'Library/PHPExcel/PHPExcel.php'; // TODO: 给予加载优化
            foreach ($excel_head_map as $key => $v) {
                if (is_numeric($key)) {
                    $excel_head_map[\PHPExcel_Cell::stringFromColumnIndex($key)] = $v;
                    unset($excel_head_map[$key]);
                }
            }
        }
        return $excel_head_map;
    }

    /**
     * 数据导入
     * @param $file 文件名 不建议使用中文名
     * @param $sheet 读取的工作表
     * @return bool
     * @throws \PHPExcel_Exception
     * @throws \PHPExcel_Reader_Exception
     */
    public function import($file, $sheet = 0)
    {
        if (!$this->excel_head_map) {
            $this->error = '请设置Excel表的头部映射关系';
            return false;
        } else if (!is_file($file)) {
            $this->error = '数据文件不存在';
            return false;
        }
        // 重新格式化一次映射关系
        $this->excel_head_map = $this->format_excel_head($this->excel_head_map);
        $exts                 = pathinfo($file, PATHINFO_EXTENSION);// 获取后缀名
        # 如果excel文件后缀名为.xls，导入这个类
        # 创建一个读Excel模板的对象
        if ($exts == 'xls') {
            require_once APP_PATH . 'Library/PHPExcel/PHPExcel/Reader/Excel5.php';// TODO: 给予加载优化
            $PHPReader = new \PHPExcel_Reader_Excel5();
        } else if ($exts == 'xlsx') {
            require_once APP_PATH . 'Library/PHPExcel/PHPExcel/Reader/Excel2007.php';// TODO: 给予加载优化
            $PHPReader = new \PHPExcel_Reader_Excel2007();
        }

        # 载入文件
        $PHPExcel     = $PHPReader->load($file);
        $currentSheet = $PHPExcel->getSheet($sheet);
        # 获取总列数
        $allColumn = \PHPExcel_Cell::columnIndexFromString($currentSheet->getHighestColumn());// 列数转换成数字才符合for循环规则
        # 获取总行数
        $allRow  = $currentSheet->getHighestRow();
        $success = 0;
        # 循环获取表中的数据，$currentRow表示当前行，从哪行开始读取数据，索引值从0开始
        for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
            $data = array();
            # 从哪列开始，A表示第一列
            for ($currentColumn = 0; $currentColumn < $allColumn; $currentColumn++) {
                # 数据坐标
                $cc      = \PHPExcel_Cell::stringFromColumnIndex($currentColumn);// 将列数转为类似AA、AB的列名
                $address = $cc . $currentRow;
                # 读取到的数据，保存到数组$data中
                $cell = $currentSheet->getCell($address)->getValue();
                if ($cell instanceof \PHPExcel_RichText) {
                    $cell = $cell->__toString();
                }
                $field        = $this->excel_head_map[$cc][0];
                $data[$field] = $cell;
            }
            $data['addtime'] = time();
            $data['mid']     = LoginState::getLoginID();
            $data['ip']      = get_client_ip();
            if (!$data['no']) {
                $data['no'] = $this->count() + 1;
            }
            $data = $this->create($data);
            if ($data) {
                $data = array_filter($data);
                if ($data) {
                    if (method_exists($this, 'addData')) {
                        // 验证
                        $res = $this->addData($data);
                    } else {
                        // 系统写入
                        $this->add($data);
                    }
                }
                if ($res) $success++;
            }
        }
        if ($success == 0) {
            $this->error = '所有数据都没有被导入, 请检查Excel表是否填写正确';
            return false;
        }
        return true;
    }

    /**
     * 数据导出
     * 使用方法：$model->where()->order()->export($filename); 支持连贯操作
     * @param $filename
     * @param $sheet 读取的工作表
     * @return bool
     * @throws PHPExcel_Exception
     * @throws PHPExcel_Reader_Exception
     * @throws PHPExcel_Writer_Exception
     */
    public function export($filename, $sheet = 0)
    {
        if (!$this->excel_head_map) {
            $this->error = '请设置Excel表的头部映射关系';
            return false;
        }
        require_once APP_PATH . 'Library/PHPExcel/PHPExcel.php';// TODO: 给予加载优化
        $this->excel_head_map = $this->format_excel_head($this->excel_head_map);
        # 创建一个读Excel模板的对象
        $objPHPExcel = new \PHPExcel();
        foreach ($this->excel_head_map as $key => $row) {
            $objPHPExcel->setActiveSheetIndex($sheet)
                ->setCellValue($key . '1', $row[1]);
            $objPHPExcel->getActiveSheet()->getStyle($key)->getNumberFormat()
                ->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);
        }
        ini_set('memory_limit', '1024M');
        $data = $this->select(); // 保留连贯 开始查询
        $num  = 2;
        foreach ($data as $key => $value) {
            foreach ($this->excel_head_map as $k => $v) {
                $objPHPExcel->getActiveSheet(0)->setCellValue($k . $num, $value[$v[0]]);
            }
            $num++;
        }
        # 导出 - excel文件名称
        # 转换名称编码，防止乱码
        $filename = iconv('utf-8', "gb2312", $filename);
        # 清除缓冲区,避免乱码
        ob_end_clean();
        header('Content-Type: application/vnd.ms-excel;charset=utf-8');
        header('Content-Disposition: attachment;filename="' . $filename . '.xls"'); //”‘.$filename.’.xls”
        header('Cache-Control: max-age=0');

        # 在内存中准备一个excel2003文件
        $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
        $objWriter->save('php://output');
    }

    public function crop_format($data)
    {
        return D('Common', 'Logic')->crop_format($data);
    }

    public function compare2del($new, $old)
    {
        D('Common', 'Logic')->compare2del($new, $old);
    }

    public function img_base64($v)
    {
        $ser = D('File', 'Service');
        $res = $ser->mutiple_save_base64img($v);
        if (count($res) == 1) {
            return reset($res);
        } else if (count($res) < 1) {
            return '';
        }
        $res = json_encode($res);
        return $res ? $res : '';
    }
}